home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 41 / Amiga Format CD41 (1999-06)(Future Publishing)(GB)[!][issue 1999-07].iso / -seriously_amiga- / programming / other / gtlayout / source / lt_menucontroltaglist.c < prev    next >
C/C++ Source or Header  |  1999-04-19  |  9KB  |  402 lines

  1. /*
  2. **    GadTools layout toolkit
  3. **
  4. **    Copyright © 1993-1998 by Olaf `Olsen' Barthel
  5. **        Freely distributable.
  6. **
  7. **    :ts=4
  8. */
  9.  
  10. #ifndef _GTLAYOUT_GLOBAL_H
  11. #include "gtlayout_global.h"
  12. #endif
  13.  
  14. /*****************************************************************************/
  15.  
  16. #include <stddef.h>
  17. #include <stdarg.h>
  18.  
  19. /*****************************************************************************/
  20.  
  21. #include "Assert.h"
  22.  
  23. /*****************************************************************************/
  24.  
  25. #ifdef DO_MENUS    /* Support code */
  26.  
  27. /****** gtlayout.library/LT_MenuControlTagList ******************************************
  28. *
  29. *   NAME
  30. *    LT_MenuControlTagList -- Manipulate menus, menu/submenu items (V11)
  31. *
  32. *   SYNOPSIS
  33. *    LT_MenuControlTagList(Window,Menu,Tags)
  34. *                           A0   A1     A2
  35. *
  36. *    VOID LT_MenuControlTagList(struct Window *,struct Menu *,struct TagItem *);
  37. *
  38. *    VOID LT_MenuControlTags(struct Window *,struct Menu *,...);
  39. *
  40. *   FUNCTION
  41. *    This routine provides a rather efficient way to set and to clear,
  42. *    to enable and to disable a number of menus, menu/submenu items
  43. *    all at once.
  44. *
  45. *    In v18 this routine was modified to disconnect a menu strip
  46. *    from a window if it is about to change checkmark states. In
  47. *    earlier releases or if a single menu is attached to several
  48. *    windows it is recommended that you disconnect the menu from
  49. *    the windows it is attached to before you call this routine.
  50. *
  51. *    As of v18 this routine is smart enough to handle menu
  52. *    mutual exclusion.
  53. *
  54. *   INPUTS
  55. *    Window - Pointer to Window this menu is attached to. Starting with
  56. *             gtlayout.library v16 this parameter may be NULL.
  57. *
  58. *    Menu - Pointer to Menu structure as returned by LT_NewMenuTagList.
  59. *
  60. *    Tags - Pointer to a list of tagitem values, as found
  61. *           in gtlayout.h
  62. *
  63. *
  64. *    Tags:
  65. *
  66. *    LAMN_ID (ULONG) - Unique ID of menu/menu item/submenu item to
  67. *        manipulate.
  68. *
  69. *    LAMN_Checked (BOOL) - Set the checkmark state of the
  70. *        menu/submenu item.
  71. *
  72. *    LAMN_Disabled (BOOL) - Set the availability state of the
  73. *        menu/menu item/submenu item.
  74. *
  75. *    LAMN_FullMenuNum (UWORD) - Intuition menu number of
  76. *        menu/submenu item to manipulate. You would pass the
  77. *        result of the FULLMENUNUM() macro here for the
  78. *        item in question. (V30)
  79. *
  80. *   RESULT
  81. *    none
  82. *
  83. *   EXAMPLE
  84. *    The following tagitem list will clear the checkmark and
  85. *    disable the menu item associated with ID 5 and set the
  86. *    checkmark for the item associated with ID 6:
  87. *
  88. *        LAMN_ID,         5,
  89. *          LAMN_Checked,  FALSE,
  90. *          LAMN_Disabled, TRUE,
  91. *        LAMN_ID,         6,
  92. *          LAMN_Checked,  TRUE,
  93. *        TAG_DONE
  94. *
  95. *   BUGS
  96. *    In library versions up to and including v17.2 this routine
  97. *    is broken. It won't do any harm, it just doesn't do what you
  98. *    want it to do.
  99. *
  100. *    Up to and including V42.1 the library could fail to find the
  101. *    correct menu items corresponding to the LAMN_ID given. This
  102. *    has been fixed in V43.1.
  103. *
  104. *    Up to and including V43.1 trying to change the attributes
  105. *    of an item with LAMN_ID whose ID number could not be found
  106. *    could lead to a crash. This has been fixed in V43.2.
  107. *
  108. *   SEE ALSO
  109. *    gtlayout.library/LT_NewMenuTagList
  110. *
  111. ******************************************************************************
  112. *
  113. */
  114.  
  115. VOID LIBENT
  116. LT_MenuControlTagList(REG(a0) struct Window *Window,REG(a1) struct Menu *IntuitionMenu,REG(a2) struct TagItem *Tags)
  117. {
  118.     RootMenu *            Root = (RootMenu *)((ULONG)IntuitionMenu - offsetof(RootMenu,Menu));
  119.     struct TagItem *    List;
  120.     struct TagItem *    Entry;
  121.     ULONG                ID;
  122.     MenuNode *            Menu = NULL;
  123.     ItemNode *            Item = NULL;
  124.     BOOL                GotIt;
  125.     BOOL                Disconnected = FALSE;
  126.  
  127.     if(!IntuitionMenu)
  128.         return;
  129.  
  130.     List = Tags;
  131.  
  132.         // Make sure that if window and menu are provided,
  133.         // the menu is attached to the window.
  134.  
  135.     if(Window && IntuitionMenu)
  136.     {
  137.         if(Window->MenuStrip != IntuitionMenu)
  138.             Window = NULL;
  139.     }
  140.  
  141.     while(Entry = NextTagItem(&List))
  142.     {
  143.         switch(Entry->ti_Tag)
  144.         {
  145.                 // We start with a menu/item/subitem ID
  146.  
  147.             case LAMN_ID:
  148.  
  149.                 GotIt = FALSE;
  150.  
  151.                 ID = (ULONG)Entry->ti_Data;
  152.  
  153.                     // Check if it's on the menu list
  154.  
  155.                 for(Menu = (MenuNode *)Root->MenuList.mlh_Head ; Menu->Node.mln_Succ ; Menu = (MenuNode *)Menu->Node.mln_Succ)
  156.                 {
  157.                     if(Menu->ID == ID)
  158.                     {
  159.                         GotIt = TRUE;
  160.  
  161.                         Item = NULL;
  162.  
  163.                         break;
  164.                     }
  165.                 }
  166.  
  167.                     // If it isn't, check the item/subitem list
  168.  
  169.                 if(!GotIt)
  170.                 {
  171.                     for(Item = (ItemNode *)Root->ItemList.mlh_Head ; Item->Node.mln_Succ ; Item = (ItemNode *)Item->Node.mln_Succ)
  172.                     {
  173.                         if(Item->ID == ID)
  174.                         {
  175.                             GotIt = TRUE;
  176.  
  177.                             Menu = NULL;
  178.  
  179.                             break;
  180.                         }
  181.                     }
  182.                 }
  183.  
  184.                     // Do nothing if none is found
  185.  
  186.                 if(!GotIt)
  187.                 {
  188.                     Menu = NULL;
  189.                     Item = NULL;
  190.                 }
  191.  
  192.                 break;
  193.  
  194.                 // We start with a menu/item/subitem ID
  195.  
  196.             case LAMN_FullMenuNum:
  197.  
  198.                 GotIt = FALSE;
  199.  
  200.                 ID = (ULONG)Entry->ti_Data;
  201.  
  202.                     // Check if it's on the menu list
  203.  
  204.                 for(Menu = (MenuNode *)Root->MenuList.mlh_Head ; Menu->Node.mln_Succ ; Menu = (MenuNode *)Menu->Node.mln_Succ)
  205.                 {
  206.                     if(Menu->MenuCode == ID)
  207.                     {
  208.                         GotIt = TRUE;
  209.  
  210.                         Item = NULL;
  211.  
  212.                         break;
  213.                     }
  214.                 }
  215.  
  216.                     // If it isn't, check the item/subitem list
  217.  
  218.                 if(!GotIt)
  219.                 {
  220.                     for(Item = (ItemNode *)Root->ItemList.mlh_Head ; Item->Node.mln_Succ ; Item = (ItemNode *)Item->Node.mln_Succ)
  221.                     {
  222.                         if(Item->MenuCode == ID)
  223.                         {
  224.                             GotIt = TRUE;
  225.  
  226.                             Menu = NULL;
  227.  
  228.                             break;
  229.                         }
  230.                     }
  231.                 }
  232.  
  233.                     // Do nothing if none is found
  234.  
  235.                 if(!GotIt)
  236.                 {
  237.                     Menu = NULL;
  238.                     Item = NULL;
  239.                 }
  240.  
  241.                 break;
  242.  
  243.                 // Fiddle with the checkmark
  244.  
  245.             case LAMN_Checked:
  246.  
  247.                 if(Item)
  248.                 {
  249.                         // Disconnect the window menu before we
  250.                         // change the states
  251.  
  252.                     if(Window && !Disconnected)
  253.                     {
  254.                         ClearMenuStrip(Window);
  255.  
  256.                         Disconnected = TRUE;
  257.                     }
  258.  
  259.                     if(Entry->ti_Data)
  260.                         Item->Item.Flags |=  CHECKED;
  261.                     else
  262.                         Item->Item.Flags &= ~CHECKED;
  263.  
  264.                         // Now check for mutual exclusion
  265.  
  266.                     if(Item->Item.MutualExclude && Entry->ti_Data)
  267.                     {
  268.                         ItemNode    *Node;
  269.                         ULONG         Exclude;
  270.                         LONG         Result;
  271.                         BOOL         IsSub;
  272.  
  273.                         Exclude = Item->Item.MutualExclude;
  274.  
  275.                             // Is the current item a submenu item?
  276.  
  277.                         if(SUBNUM(Item->MenuCode) == NOSUB)
  278.                             IsSub = FALSE;
  279.                         else
  280.                             IsSub = TRUE;
  281.  
  282.                             // Walk the item list back to the first list entry
  283.                             // in this menu/submenu
  284.  
  285.                         for(Node = Item ; Node->Node.mln_Pred ; Node = (ItemNode *)Node->Node.mln_Pred)
  286.                         {
  287.                                 // Extract the item number
  288.  
  289.                             if(IsSub)
  290.                                 Result = SUBNUM(Node->MenuCode);
  291.                             else
  292.                                 Result = ITEMNUM(Node->MenuCode);
  293.  
  294.                                 // Is this the first item?
  295.  
  296.                             if(!Result)
  297.                             {
  298.                                 LONG i,Mask,Value;
  299.  
  300.                                     // Now build a mask to extract the data
  301.                                     // that should remain constant for all
  302.                                     // items in this list.
  303.  
  304.                                 if(IsSub)
  305.                                     Mask = 0x07FF;    // menu-item + menu
  306.                                 else
  307.                                     Mask = 0x001F;    // menu
  308.  
  309.                                     // This is the constant value
  310.  
  311.                                 Value = Item->MenuCode & Mask;
  312.  
  313.                                     // Now we walk down the list
  314.  
  315.                                 for(i = 0 ; Node->Node.mln_Succ && i < 32 ; i++)
  316.                                 {
  317.                                         // Will this one be affected by the
  318.                                         // mutual exclusion stuff?
  319.  
  320.                                     if(Node != Item && (Node->Item.Flags & CHECKIT) && (Exclude & (1L << i)))
  321.                                         Node->Item.Flags &= ~CHECKED;
  322.  
  323.                                         // Move to the next item
  324.  
  325.                                     Node = (ItemNode *)Node->Node.mln_Succ;
  326.  
  327.                                         // Is this still the same menu/submenu?
  328.  
  329.                                     if((Node->MenuCode & Mask) != Value)
  330.                                         break;
  331.                                 }
  332.  
  333.                                 break;
  334.                             }
  335.                         }
  336.                     }
  337.                 }
  338.  
  339.                 break;
  340.  
  341.                 // Turn menus, submenus and items off or on
  342.  
  343.             case LAMN_Disabled:
  344.  
  345.                 if(Item != NULL || Menu != NULL)
  346.                 {
  347.                     if(Window != NULL)
  348.                     {
  349.                         LONG Code;
  350.  
  351.                         if(Item != NULL)
  352.                             Code = Item->MenuCode;
  353.                         else
  354.                             Code = Menu->MenuCode;
  355.  
  356.                         if(Entry->ti_Data)
  357.                             OffMenu(Window,Code);
  358.                         else
  359.                             OnMenu(Window,Code);
  360.                     }
  361.                     else
  362.                     {
  363.                         UWORD *Flags;
  364.  
  365.                         if(Item)
  366.                             Flags = &Item->Item.Flags;
  367.                         else
  368.                             Flags = &Menu->Menu.Flags;
  369.  
  370.                         if(Entry->ti_Data)
  371.                             *Flags &= ~ITEMENABLED;
  372.                         else
  373.                             *Flags |= ITEMENABLED;
  374.                     }
  375.                 }
  376.  
  377.                 break;
  378.         }
  379.     }
  380.  
  381.         // Reconnect the menu strip if necessary
  382.  
  383.     if(Disconnected)
  384.         ResetMenuStrip(Window,IntuitionMenu);
  385. }
  386.  
  387.  
  388. /*****************************************************************************/
  389.  
  390.  
  391. VOID
  392. LT_MenuControlTags(struct Window *Window,struct Menu *Menu,...)
  393. {
  394.     va_list VarArgs;
  395.  
  396.     va_start(VarArgs,Menu);
  397.     LT_MenuControlTagList(Window,Menu,(struct TagItem *)VarArgs);
  398.     va_end(VarArgs);
  399. }
  400.  
  401. #endif    /* DO_MENUS */
  402.